using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using QFramework.Example;
using UnityEngine;
namespace QFramework
{
    public class SlotGroup
    {
	    /// <summary>
	    /// 格子组的key标识
	    /// </summary>
        public string Key=String.Empty;
	    
	    /// <summary>
	    /// 格子组中包含的所有格子
	    /// </summary>
        private List<Slot> mSlots = new List<Slot>();

        /// <summary>
        /// slot是否满足条件，比如当前格子是装备格子，拖进来的是否装备，是则可以穿，不是则忽略
        /// </summary>
        private Func<IItem, bool> mCondition = _ => true;

        /// <summary>
        /// 当该格子发生变化时，如道具改变，数量改变等，会触发该事件
        /// </summary>
        public EasyEvent Changed = new EasyEvent();
        
        public bool CheckCondition(IItem item)
        {
            return mCondition(item);
        }
        
        public IReadOnlyList<Slot> Slots => mSlots;

        /// <summary>
        /// 获取当前栏对应物品的数量
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public int GetItemCount(IItem item)
        {
	        return Slots
		        .Where(slot => slot.Count > 0 && slot.Item == item)
		        .Sum(slot => slot.Count);
        }
        
        /// <summary>
        /// 创建格子道具
        /// </summary>
        /// <param name="item"></param>
        /// <param name="count"></param>
        public SlotGroup CreateSlot(IItem item, int count)
        {
            mSlots.Add(new Slot(item,count,this));
            Changed.Trigger();
            return this;
        }
        
        public SlotGroup CreateSlotByKey(string itemKey,int count)
        {
            return CreateSlot(ItemKit.ItemByKey[itemKey], 1);
        }
        
        /// <summary>
        /// 创建指定数量的格子
        /// </summary>
        /// <param name="count"></param>
        /// <returns></returns>
        public SlotGroup CreateSlotsByCount(int count)
        {
            for (var i = 0; i < count; i++)
            {
                CreateSlot(null, 0);
            }
            Changed.Trigger();
            return this;
        }
        
		/// <summary>
        /// 查找对应key的格子
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public Slot FindSlotByKey(string key)
        {
        	return mSlots.Find(s => s.Item != null && s.Item.GetKey == key && s.Count != 0);
        }

        /// <summary>
        /// 查找空格子
        /// </summary>
        /// <returns></returns>
        public Slot FindEmptySlot()
        {
        	return mSlots.Find(s => s.Count == 0);
        }

        /// <summary>
        /// 找到可以添加物品的格子
        /// </summary>
        /// <param name="itemKey">物品ID</param>
        /// <returns></returns>
        public Slot FindAddableSlot(string itemKey)
        {
	        var item = ItemKit.ItemByKey[itemKey];
	        // 如果不可堆叠，则找空格子添加，否则找已有同样物品的格子添加
	        if (!item.IsStackable)
	        {
		        var slot = FindEmptySlot();
		        if (slot!=null)
		        {
			        slot.Item = item;
		        }

		        return slot;
	        }
	        else if (item.IsStackable&&!item.GetHasMaxStackableCount)
	        {
		        var slot = FindSlotByKey(itemKey);
		        if (slot==null)
		        {
			        slot = FindEmptySlot();
			        if (slot!=null)
			        {
				        slot.Item = ItemKit.ItemByKey[itemKey];
			        }
		        }

		        return slot;
	        }
	        else
	        {
		        return FindAddableHasMaxStackableCountSlot(itemKey);
	        }

	        return null;
        }
        
        /// <summary>
        /// 查找对应Key的其它格子里没有叠满的格子
        /// </summary>
        /// <param name="itemKey"></param>
        /// <returns></returns>
        public Slot FindAddableHasMaxStackableCountSlot(string itemKey)
        {
	        foreach (var slot in mSlots)
	        {
		        if (slot.Count != 0 && slot.Item.GetKey == itemKey && slot.Item.GetMaxStackableCount > slot.Count)
		        {
			        return slot;
		        }
	        }
	        
	        var emptySlot = FindEmptySlot();
	        if (emptySlot!=null)
	        {
		        emptySlot.Item=ItemKit.ItemByKey[itemKey];
	        }
	        return emptySlot;
        }

        public struct ItemOperateResult
        {
	        public bool Succeed;
	        // 堆叠后剩余的数量，也就是格子放满了还剩下的数量
	        public int RemainCount;
	        public MessageTypes MessageTypes;
        }
        
        /// <summary>
        /// 信息类别，作为判断，比如格子满了
        /// </summary>
        public enum MessageTypes
        {
	        Full,//满了
        }
        
        /// <summary>
        /// 格子中添加道具
        /// </summary>
        /// <param name="itemKey">道具Key</param>
        /// <param name="addCount">添加的数量</param>
        /// <returns></returns>
        public ItemOperateResult AddItem(string itemKey,int addCount=1)
        {
	        var item = ItemKit.ItemByKey[itemKey];
	        if (item.IsStackable&&item.GetHasMaxStackableCount)
	        {
		        do
		        {
			        var slot = FindAddableHasMaxStackableCountSlot(itemKey);
			        if (slot!=null)
			        {
				        // 计算当前slot剩余的堆叠数量
				        var canAddCount = slot.Item.GetMaxStackableCount - slot.Count;
				        // 如果需要增加的数量小于等于剩余的堆叠数量，则直接增加
				        if (addCount<=canAddCount)
				        {
					        slot.Count += addCount;
					        slot.Changed.Trigger();
					        Changed.Trigger();
					        // return new ItemOperateResult() { Succeed = true, RemainCount = 0 };
					        addCount = 0;
				        }
				        else
				        {
					        // 如果需要增加的数量大于剩余的堆叠数量，则增加剩余的堆叠数量，并返回剩余的堆叠数量
					        slot.Count += canAddCount;
					        slot.Changed.Trigger();
					        Changed.Trigger();
				        
					        addCount -= canAddCount;
				        }
			        }
			        else
			        {
				        // 没有格子，无法添加，把需要增加的数量返回
				        return new ItemOperateResult() { Succeed = false, RemainCount = addCount };
			        }
		        }while (addCount>0);// 循环直到添加完成
		        
		        return new ItemOperateResult() { Succeed = true, RemainCount = 0 };
	        }
	        else
	        {
		        var slot = FindAddableSlot(itemKey);
		        if (slot==null)
		        {
			        //Debug.Log("背包满了");
			        return new ItemOperateResult(){Succeed = false};
		        }
		        slot.Count+=addCount;
		        // 增加道具后要刷新显示
		        slot.Changed.Trigger();
		        Changed.Trigger();
		        return new ItemOperateResult() { Succeed = true, RemainCount = 0 };
	        }
        }
        
        public ItemOperateResult AddItem(IItem item,int addCount=1)
        {
	        return AddItem(item.GetKey,addCount);
        }

        /// <summary>
        /// 格子中减少道具
        /// </summary>
        /// <param name="itemKey">道具Key</param>
        /// <param name="subCount">减少的数量</param>
        /// <returns></returns>
        public bool SubItem(string itemKey, int subCount = 1)
        {
        	var slot = FindSlotByKey(itemKey);
        	if (slot!=null && slot.Count>=subCount)
        	{
        		slot.Count-=subCount;
		        slot.Changed.Trigger();
		        Changed.Trigger();
        		return true;
        	}
	        else if (slot!=null)
	        {
		        subCount -= slot.Count;
		        slot.Count = 0;
		        slot.Changed.Trigger();
		        //Changed.Trigger();
		        return SubItem(itemKey, subCount);
	        }
        	//Debug.Log("删除的道具为空，或删除的数量大于当前的数量");
        	return false;
        }

        public bool SubItem(IItem item, int subCount = 1)
        {
	        return SubItem(item.GetKey,subCount);
        }

        /// <summary>
        /// 设置格子组条件，在创建的时候设置该格子组是什么类型，比如装备格子，那这个格子只能放装备
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        public SlotGroup Condition(Func<IItem, bool> condition)
        {
	        mCondition = condition;
	        return this;
        }
    }
}
